#include "hisoc/mmc.h"

#define IOCFG_REG33 (0x112C0048)

#define SDIO_MODE_DS_DRV 7
#define SDIO_MODE_HS_DRV 5
#define SDIO_MODE_HS_DRV_MSK 0xf
#define SDIO_MODE_HS_DRV_SHIFT 4

#define DRV_PHASE_112P5_DEGREE         10         /* 112.5 degree */
#define DRV_PHASE_258P75_DEGREE       23         /* 258.75 degree */
#define DRV_PHASE_225_DEGREE            20          /* 225 degree */
#define DRV_PHASE_180_DEGREE            16          /* 180 degree */

#define SAMPLE_PHASE 4

#define IO_DRV_SD_SDHS_CLK  0x5
#define IO_DRV_SD_SDHS_CMD  0x7
#define IO_DRV_SD_SDHS_DATA 0x7

#define IO_DRV_SD_OTHER_CLK  0x7
#define IO_DRV_SD_OTHER_CMD   IO_DRV_SD_OTHER_CLK
#define IO_DRV_SD_OTHER_DATA  IO_DRV_SD_OTHER_CLK

#define IO_DRV_EMMC_HS400_CLK  0x3
#define IO_DRV_EMMC_HS400_CMD  0x4
#define IO_DRV_EMMC_HS400_DATA 0x4
#define IO_DRV_EMMC_HS400_DS   0x3
#define IO_DRV_EMMC_HS400_RST  0x3

#define IO_DRV_EMMC_HS200_CLK  0x2
#define IO_DRV_EMMC_HS200_CMD  0x4
#define IO_DRV_EMMC_HS200_DATA 0x4
#define IO_DRV_EMMC_HS200_RST  0x3

#define IO_DRV_EMMC_HS_CLK  0x4
#define IO_DRV_EMMC_HS_CMD  0x6
#define IO_DRV_EMMC_HS_DATA 0x6
#define IO_DRV_EMMC_HS_RST  0x3

#define IO_DRV_EMMC_OTHER_CLK  0x5
#define IO_DRV_EMMC_OTHER_CMD  0x6
#define IO_DRV_EMMC_OTHER_DATA 0x6
#define IO_DRV_EMMC_OTHER_RST  0x3

#define IO_DRV_SDIO_HS_CLK  0x5
#define IO_DRV_SDIO_HS_CMD  0x7
#define IO_DRV_SDIO_HS_DATA 0x7

#define IO_DRV_SDIO_SDR12_CLK  0x3
#define IO_DRV_SDIO_SDR12_CMD  0x6
#define IO_DRV_SDIO_SDR12_DATA 0x6


#define IO_DRV_SDIO_OTHER_CLK  0x5
#define IO_DRV_SDIO_OTHER_CMD  0x7
#define IO_DRV_SDIO_OTHER_DATA 0x7


int mmc_voltage_switch(struct mmc_host *mmc, enum signal_volt signal_voltage)
{
#if defined(LOSCFG_DRIVERS_SD_PROT_VER3)
    if (signal_voltage == SIGNAL_VOLT_1V8) {
        return 0;
    } else {
        return -EAGAIN;
    }
#else
    if (signal_voltage == SIGNAL_VOLT_3V3) {
        return 0;
    } else {
        return -EAGAIN;
    }
#endif
}

unsigned int sdhci_set_clock(struct sdhc_host *host, unsigned int cfg_clock) /*lint -e550 -e574*/
{
    unsigned int reg = 0, temp = 0, value = 0;
    unsigned int cfgArray[] = {PERI_CRG125, PERI_CRG139};

    if (host->id > 1) {
        mmc_err("host id=%d is not supported!\n", host->id);
        return 0;
    }

    if (host->id == 1 && (cfg_clock > MMC_FREQ_50M)) {
        mmc_err("host%d doesn't support freq %d!\n", host->id, cfg_clock);
        return 0;
    }

    if (cfg_clock >= MMC_FREQ_150M) {
        temp |= 6;
    } else if (cfg_clock >= MMC_FREQ_112P5M) {
        temp |= 5;
    } else if (cfg_clock >= MMC_FREQ_90M) {
        temp |= 4;
    } else if (cfg_clock >= MMC_FREQ_50M) {
        temp |= 3;
    } else if (cfg_clock >= MMC_FREQ_25M) {
        temp |= 2;
    } else if (cfg_clock >= MMC_FREQ_400K) {
        temp |= 1;
    } else if (cfg_clock >= MMC_FREQ_100K) {
        temp = 0;
    } else {
        temp = 0;
    }

    reg = cfgArray[host->id];
    value = readl(reg);
    value &= ~(MMC_FREQ_MASK << MMC_FREQ_SHIFT);
    value |= ((temp & MMC_FREQ_MASK) << MMC_FREQ_SHIFT);
    value |= SDIO0_CKEN; // clock enable
    writel(value, reg);

    return cfg_clock;
} /*lint +e550 +e574*/

void sdhci_set_bus_width(struct sdhc_host *host, int width)
{

}

void sdhci_hisi_assert_reset_dll(struct sdhc_host *host)
{
    unsigned int reg, value;
    unsigned int cfgArray[] = {PERI_CRG125, PERI_CRG139};

    if (host->id > 1) {
        return;
    }

    // crg_reset, dll_reset, sampl_reset
    reg = cfgArray[host->id];
    value = readl(reg);
    value |= PERI_CRG106_EMMC_DLL_RST;
    writel(value, reg);
}

void sdhci_hisi_deassert_reset_dll(struct sdhc_host *host)
{
    unsigned int reg, value;
    unsigned int cfgArray[] = {PERI_CRG125, PERI_CRG139};

    if (host->id > 1) {
        return;
    }

    // crg_reset, dll_reset, sampl_reset
    reg = cfgArray[host->id];
    value = readl(reg);
    value &= ~PERI_CRG106_EMMC_DLL_RST;
    writel(value, reg);
}
void sdhci_hisi_set_drv_dll(struct sdhc_host *host)
{
}
void sdhci_hisi_sam_dll_slave_en(struct sdhc_host *host,
                                 unsigned int phase)
{
}
void sdhci_hisi_set_samp_phase(struct sdhc_host *host, unsigned int phase)
{
    unsigned int reg;
    reg = sdhc_readl(host, SDHC_AUTO_TUNING_STATUS);
    reg &= ~SDHC_CENTER_PH_CODE_MASK;
    reg |= phase;
    sdhc_writel(host, reg, SDHC_AUTO_TUNING_STATUS);
}
void sdhci_set_uhs_signaling(struct sdhc_host *host, enum mmc_bus_timing timing)
{
    unsigned int ctrl_2 = 0;

    ctrl_2 = sdhc_readw(host, SDHC_HOST_CONTROL2);

    /* Select Bus Speed Mode for host */
    ctrl_2 &= ~SDHC_CTRL_UHS_MASK;
    if ((timing == TIMING_MMC_HS200) ||
            (timing == TIMING_UHS_SDR104)) {
        ctrl_2 |= SDHC_CTRL_UHS_SDR104;
    } else if (timing == TIMING_UHS_SDR12) {
        ctrl_2 |= SDHC_CTRL_UHS_SDR12;
    } else if (timing == TIMING_UHS_SDR25) {
        ctrl_2 |= SDHC_CTRL_UHS_SDR25;
    } else if (timing == TIMING_UHS_SDR50) {
        ctrl_2 |= SDHC_CTRL_UHS_SDR50;
    } else if ((timing == TIMING_UHS_DDR50) ||
               (timing == TIMING_UHS_DDR52)) {
        ctrl_2 |= SDHC_CTRL_UHS_DDR50;
    } else if (timing == TIMING_MMC_HS400) {
        ctrl_2 |= SDHC_CTRL_HS400;
    }
    sdhc_writew(host, ctrl_2, SDHC_HOST_CONTROL2);
}

void sdhci_host_quirks(struct sdhc_host *host)
{
    switch (host->id) {
        case MMC0:
            host->flags &= ~(SDHC_CAN_DO_SDMA);
            host->flags |= SDHC_AUTO_CMD23;
            break;
#if USE_MMC1
        case MMC1:
            host->flags &= ~(SDHC_CAN_DO_SDMA | SDHC_AUTO_CMD23 | SDHC_AUTO_CMD12);
            break;
#endif
        default:
            break;
    }

}

void sdhc_merge(struct sdhc_host *host, int addr, unsigned int val, unsigned int mask)
{
    unsigned int value;
    value = sdhc_readl(host, addr);
    value &= ~mask;
    value |= val;
    sdhc_writel(host, value, addr);
}

void sdhci_pltfm_set_io(struct sdhc_host *host)
{
    switch (host->id) {
        case 0:  /* SDIO0 OR EMMC */
            break;
#if USE_MMC1
        case 1:
            break;
#endif
        default:
            return;
    }
}

static void SDHCI_SetDrvPhase(struct sdhc_host *host, unsigned int phase)
{
    unsigned int value;
    unsigned int drv[] = {PERI_CRG127, PERI_CRG136};

    if (host->id > 1) {
        return;
    }

    // SAM/DRV
    value = readl(drv[host->id]);
    value &= ~PERI_SAM_DRV_MASK;
    value |= (phase << PERI_SAM_DRV_SHFT);
    writel(value, drv[host->id]);
}

static void SDHCI_SetIo(unsigned int offset, unsigned int val)
{
    unsigned int reg;

    reg = readl(offset);
    reg &= ~IO_DRV_MASK;
    reg |= val & IO_DRV_MASK;
    writel(reg, offset);
}

static void SDHCI_SetIodriver(unsigned int offset,
                              unsigned int pull, unsigned int sr, unsigned int drv)
{
    SDHCI_SetIo(offset, pull | (sr ? IO_CFG_SR : 0) | IO_DRV_STR_SEL(drv));
}


static void SDHCI_SetSddriver(struct sdhc_host *host)
{
    int i, count;
    enum mmc_bus_timing timing;
    struct mmc_card *cardCurrent = host->mmc->card_cur;
    unsigned int dataRegs[] = {REG_CTRL_SDIO0_DATA0, REG_CTRL_SDIO0_DATA1, REG_CTRL_SDIO0_DATA2, REG_CTRL_SDIO0_DATA3};

    if (cardCurrent == NULL) {
        return;
    }

    timing = cardCurrent->iocfg.timing;
    count = ARRAY_SIZE(dataRegs);

    switch (timing) {
        case TIMING_SD_HS:
            SDHCI_SetIodriver(REG_CTRL_SDIO0_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SD_SDHS_CLK);
            SDHCI_SetIodriver(REG_CTRL_SDIO0_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_SDHS_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_SDHS_DATA);
            }
            break;
        default:
            SDHCI_SetIodriver(REG_CTRL_SDIO0_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SD_OTHER_CLK);
            SDHCI_SetIodriver(REG_CTRL_SDIO0_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_OTHER_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SD_OTHER_DATA);
            }
            break;
    }
}

static void SDHCI_SetEmmcCtrl(struct sdhc_host *host)
{
    unsigned int reg;

    reg = sdhc_readl(host, SDHC_EMMC_CTRL);
    reg |= SDHC_EMMC_CTRL_EMMC;
    sdhc_writel(host, reg, SDHC_EMMC_CTRL);
}


static void SDHCI_SetEmmcDriver(struct sdhc_host *host)
{
    int i;
    struct mmc_card *cardCurrent = host->mmc->card_cur;
    unsigned int dataRegs[] = {REG_CTRL_EMMC_DATA0, REG_CTRL_EMMC_DATA1, REG_CTRL_EMMC_DATA2, REG_CTRL_EMMC_DATA3,
                               REG_CTRL_EMMC_DATA4, REG_CTRL_EMMC_DATA5, REG_CTRL_EMMC_DATA6, REG_CTRL_EMMC_DATA7
                              };
    int count = ARRAY_SIZE(dataRegs);

    if (cardCurrent == NULL) {
        return;
    }

    switch (cardCurrent->iocfg.timing) {
        case TIMING_MMC_HS400:
            SDHCI_SetEmmcCtrl(host);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, 0, IO_DRV_EMMC_HS400_CLK);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, 0, IO_DRV_EMMC_HS400_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, 0, IO_DRV_EMMC_HS400_DATA);
            }
            SDHCI_SetIodriver(REG_CTRL_EMMC_DS, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_EMMC_HS400_DS);
            SDHCI_SetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS400_RST);
            break;
        case TIMING_MMC_HS200:
            SDHCI_SetEmmcCtrl(host);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, 0, IO_DRV_EMMC_HS200_CLK);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS200_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS200_DATA);
            }
            SDHCI_SetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS200_RST);
            break;
        case TIMING_MMC_HS:
            SDHCI_SetEmmcCtrl(host);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_EMMC_HS_CLK);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS_DATA);
            }
            SDHCI_SetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_HS_RST);
            break;
        default:
            SDHCI_SetIodriver(REG_CTRL_EMMC_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_EMMC_HS_RST);
            SDHCI_SetIodriver(REG_CTRL_EMMC_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_OTHER_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_OTHER_DATA);
            }
            SDHCI_SetIodriver(REG_CTRL_EMMC_RST, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_EMMC_OTHER_RST);
            break;
    }
}



static void SDHCI_SetSdiodriver(struct sdhc_host *host)
{
    int i, count;
    enum mmc_bus_timing timing;
    struct mmc_card *cardCurrent = host->mmc->card_cur;
    unsigned int dataRegs[] = {REG_CTRL_SDIO1_DATA0, REG_CTRL_SDIO1_DATA1, REG_CTRL_SDIO1_DATA2, REG_CTRL_SDIO1_DATA3};

    if (cardCurrent == NULL) {
        return;
    }

    count = ARRAY_SIZE(dataRegs);
    timing = cardCurrent->iocfg.timing;

    switch (timing) {
        case TIMING_SD_HS:
            SDHCI_SetIodriver(REG_CTRL_SDIO1_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SDIO_HS_CLK);
            SDHCI_SetIodriver(REG_CTRL_SDIO1_CMD, IO_CFG_PULL_UP, 0, IO_DRV_SDIO_HS_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, 0, IO_DRV_SDIO_HS_DATA);
            }
            break;
        case TIMING_UHS_SDR12:
        case TIMING_UHS_SDR25:
            SDHCI_SetIodriver(REG_CTRL_SDIO1_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SDIO_SDR12_CLK);
            SDHCI_SetIodriver(REG_CTRL_SDIO1_CMD, IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SDIO_SDR12_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, IO_CFG_SR, IO_DRV_SDIO_SDR12_DATA);
            }
            break;
        default:
            SDHCI_SetIodriver(REG_CTRL_SDIO1_CLK, IO_CFG_PULL_DOWN, IO_CFG_SR, IO_DRV_SDIO_OTHER_CLK);
            SDHCI_SetIodriver(REG_CTRL_SDIO1_CMD, IO_CFG_PULL_UP, 0, IO_DRV_SDIO_OTHER_CMD);
            for (i = 0; i < count; i++) {
                SDHCI_SetIodriver(dataRegs[i], IO_CFG_PULL_UP, 0, IO_DRV_SDIO_OTHER_DATA);
            }
            break;
    }
}

static void SDHCI_SetMmcIoDriver(struct sdhc_host *host)
{
    unsigned int reg = 0;

    if (host->id == 0) {
        /* mmc0: eMMC or SD card */
        reg = readl(REG_CTRL_EMMC_CLK) & IO_MUX_MASK;
        if (reg == IO_MUX_SHIFT(IO_MUX_CLK_TYPE_EMMC)) {
            SDHCI_SetEmmcDriver(host);
        }
        reg = readl(REG_CTRL_SDIO0_CLK) & IO_MUX_MASK;
        if (reg == IO_MUX_SHIFT(IO_MUX_CLK_TYPE_SD)) {
            SDHCI_SetSddriver(host);
        }
    } else if (host->id == 1) {
        /* mmc1: SDIO WIFI */
        SDHCI_SetSdiodriver(host);
    }
}


void SDHCI_SetPhase(struct sdhc_host *host)
{
    unsigned int drvPhase, samplPhase;
    enum mmc_bus_timing timing;
    struct mmc_card *cardCurrent = NULL;

    if (host->mmc == NULL) {
        return;
    }

    cardCurrent = host->mmc->card_cur;
    if (cardCurrent == NULL) {
        return;
    }

    timing = cardCurrent->iocfg.timing;

    if (host->id == 0) {
        /* eMMC and SD card */
        if (timing == TIMING_MMC_HS400) {
            drvPhase = DRV_PHASE_112P5_DEGREE;
            samplPhase = host->tuningPhase;
        } else if (timing == TIMING_MMC_HS200) {
            drvPhase = DRV_PHASE_258P75_DEGREE;
            samplPhase = host->tuningPhase;
        } else if (timing == TIMING_MMC_HS) {
            drvPhase = DRV_PHASE_180_DEGREE;
            samplPhase = SAMPLE_PHASE;
        } else if (timing == TIMING_SD_HS) {
            drvPhase = DRV_PHASE_225_DEGREE;
            samplPhase = SAMPLE_PHASE;
        } else {
            drvPhase = DRV_PHASE_225_DEGREE;
            samplPhase = SAMPLE_PHASE;
        }
    } else {
        /* SDIO device */
        if ((timing == TIMING_SD_HS) ||
                (timing == TIMING_UHS_SDR25)) {
            drvPhase = DRV_PHASE_180_DEGREE;
            samplPhase = SAMPLE_PHASE;
        } else {
            /* UHS_SDR12 */
            drvPhase = DRV_PHASE_180_DEGREE;
            samplPhase = 0;
        }
    }

    SDHCI_SetDrvPhase(host, drvPhase);
    SDHCI_EnableSample(host);
    sdhci_hisi_set_samp_phase(host, samplPhase);
    SDHCI_SetMmcIoDriver(host);
}



void hi_mci_pad_ctrl_cfg(struct sdhc_host *host, enum signal_volt voltage)
{
    if (host->id == 0) {
        if (SIGNAL_VOLT_1V8 == voltage ||
                SIGNAL_VOLT_3V3 == voltage) {
            return;
        }
    } else if (host->id == 1) {
        if (SIGNAL_VOLT_3V3 == voltage) {
            return;
        }
    }
    mmc_err("Warning: host=%d, voltage=%d not support\n", host->id, SIGNAL_VOLT_3V3);
}

void sdhci_crg_init(struct sdhc_host *host)
{
    unsigned int value, reg;
    unsigned int cfgArray[] = {PERI_CRG125, PERI_CRG139};
    if (host->id > 1) {
        return;
    }

    //open the clock gate
    reg = cfgArray[host->id];
    value = readl(reg);
    value |= PERI_CRG106_EMMC_CKEN;
    writel(value, reg);

    //crg_reset, dll_reset, sampl_reset
    reg = cfgArray[host->id];
    value = readl(reg);
    value |= PERI_CRG106_EMMC_CRG_REQ;
    value |= PERI_CRG106_EMMC_DLL_RST;
    writel(value, reg);

    //wait the card clk close for 25us
    mmc_delay_us(25);

    //reset of host contorl is done
    value = readl(reg);
    value &= ~PERI_CRG106_EMMC_CRG_REQ;
    writel(value, reg);

    //wait it done
    mmc_delay_us(25);

    //close the clock gate
    SDHCI_CardClk(host, 0);

#if defined(LOSCFG_DRIVERS_SD_PROT_VER3)
    (void)sdhci_set_clock(host, MMC_FREQ_150M);
#else
    (void)sdhci_set_clock(host, MMC_FREQ_50M);
#endif

    //SAM/DRV
    SDHCI_SetDrvPhase(host, 0x10);

    //wait the clock switch over for 25us
    mmc_delay_us(25);

    //open the clk of interface :
    SDHCI_CardClk(host, 1);

    //open the clk of card:
    value = sdhc_readl(host, SDHC_CLK_CTRL);
    value |= 1 << 2;
    value |= 1 | SDHC_CLK_CTRL_CLK_EN | SDHC_CLK_CTRL_PLL;
    sdhc_writel(host, value, SDHC_CLK_CTRL);

    //wait the phase switch over, 75us
    mmc_delay_us(75);
}

void sdhci_pltfm_init(struct sdhc_host *host) /*lint -e550*/
{
    struct mmc_host *mmc = host->mmc;

    host->quirks.bits.quirk_broken_dma = 1;
    host->quirks.bits.quirk_data_timeout_use_sdclk = 1;
    host->quirks.bits.quirk_inverted_write_protect = 1;
    host->quirks.bits.quirk_cap_clock_base_broken = 1;
    host->quirks.bits.quirk_broken_timeout_val = 1;

    host->quirks2.bits.quirk2_broken_ddr50 = 1;
    host->quirks.bits.quirk_no_endattr_in_nopdesc = 1;

    switch (host->id) {
        case MMC0:
            mmc->freq_max = CONFIG_MMC0_CCLK_MAX;
            mmc->freq_min = CONFIG_MMC0_CCLK_MIN;
//the code bellow depends on what you connect to the chip by SDIO0, EMMC or SD card.
#if defined(LOSCFG_DRIVERS_SD_PROT_VER2)
            host->quirks2.bits.quirk2_no_1_8_v = 1;
            host->quirks2.bits.quirk2_broken_hs200 = 1;
#else
            //EMMC support 1.8v, DS/HS/DDR/HS200
            host->quirks2.bits.quirk2_no_1_8_v = 0;
            mmc->caps.bits.cap_8_bit = 1;
            mmc->caps2.bits.caps2_HS200_1v8_SDR = 1;
            mmc->caps2.bits.caps2_HS200_1v2_SDR = 1;
            mmc->ocr_default.bits.vdd_1v65_1v95 = 1;
            mmc->caps.bits.cap_nonremovable = 1;
#endif
            break;
#if USE_MMC1
        case MMC1:
            mmc->freq_max = CONFIG_MMC1_CCLK_MAX;
            mmc->freq_min = CONFIG_MMC1_CCLK_MIN;
            host->quirks2.bits.quirk2_no_1_8_v = 1;
            host->quirks2.bits.quirk2_broken_hs200 = 1;
            break;
#endif
        default:
            break;
    }
}
//config the adma address based on the platform
void sdhci_adma_config(struct sdhc_host *host)  /*lint -e550*/
{
    sdhc_writel(host, 0, SDHC_ADMA_ADDRESS_HIGH);
    sdhc_writel(host, (AARCHPTR)host->adma_desc, SDHC_ADMA_ADDRESS_LOW);
}


void SDHCI_WaitDrvDllLock(struct sdhc_host *host)
{
    unsigned int timeout = 20;
    unsigned int offset[] = {PERI_SDIO0_DRV_DLL_CTRL, PERI_SDIO1_DRV_DLL_CTRL};

    if (host->id >= ARRAY_SIZE(offset)) {
        return;
    }

    do {
        if (readl(offset[host->id]) & SDIO_DRV_DLL_LOCK) {
            return;
        }
        LOS_Mdelay(1);
        timeout--;
    } while (timeout > 0);

    mmc_err("host%d: DRV DLL master not locked.\n", host->id);
}

void SDHCI_EnSamplDllSlave(struct sdhc_host *host)
{
    unsigned int reg;
    unsigned int offset[] = {PERI_CRG125, PERI_CRG139};

    if (host->id >= ARRAY_SIZE(offset)) {
        return;
    }

    reg = readl(offset[host->id]);
    reg |= SDIO_SAMPL_DLL_SLAVE_EN;
    writel(reg, offset[host->id]);
}

void SDHCI_WaitSamplDllSlaveReady(struct sdhc_host *host)
{
    unsigned int timeout = 20;
    unsigned int offset[] = {PERI_SDIO0_SAMPL_DLL_STATUS, PERI_SDIO1_SAMPL_DLL_STATUS};

    if (host->id >= ARRAY_SIZE(offset)) {
        return;
    }
    do {
        if (readl(offset[host->id]) & SDIO_SAMPL_DLL_SLAVE_READY) {
            return;
        }
        LOS_Mdelay(1);
        timeout--;
    } while (timeout > 0);
    mmc_err("host%d: SAMPL DLL slave not ready.\n", host->id);
}
